package com.yx.filesystem.storage;

import java.math.BigInteger;
import java.util.Hashtable;
import java.util.List;
import org.json.JSONObject;

public class BackupDaemonService extends Thread {
	public static final long SLEEP_TIME = 60 * 1000;
	private Node serverNode;
	private long[] timestamps = null;
	private long[] timestampFileNumbers = null;
		
	public BackupDaemonService(Node serverNode) {
		this.serverNode = serverNode;
		long[] oldTimestamps = Archive.getTimeStamps(serverNode.getId());
		timestamps = new long[oldTimestamps.length + 1];
		timestampFileNumbers = new long[oldTimestamps.length + 1];
		for (int i = 0; i < oldTimestamps.length; i++) {
			timestamps[i] = oldTimestamps[i];
			timestampFileNumbers[i] = Archive.getMaxFileNumber(serverNode.getId(),
					oldTimestamps[i]);
		}
		timestamps[timestamps.length - 1] = Archive.NOW_TIME_STAMP;
		timestampFileNumbers[timestamps.length - 1] = getEndFileNumber();
		this.start();
		String backIpStr = "";
		List<Node> bacupkList = serverNode.getBachupNodes();
		for (int i = 0; i < bacupkList.size(); i++) {
			Node bNode = bacupkList.get(i);
			backIpStr = backIpStr+bNode.getHost() + ":" + bNode.getPort() + "  ";
		}
		System.out.println("Backup Service statup,BackupServers：" + backIpStr);
	}

	public void run() {
		while (true) {
			try {
				SpaceChecker.check();				
			} catch (Throwable e) {
			}
			try {
				List<Node> backupList = serverNode.getBachupNodes();
				for (Node n : backupList) {
					try {
						backupToOtherNode(n);
					} catch (Throwable e) {
					}
					daemonSleep(1000);
				}
			} catch (Throwable e) {
			}
			daemonSleep(SLEEP_TIME);
		}
	}

	private void backupToOtherNode(Node backupNode) {
		boolean isConnect = false;
		int beginTimeStampPointer = 0;
		long beginStorateFileNumber = -1;
		long backupStorateTimeStamp = timestamps[0];
		SocketClient client = new SocketClient();
		try {
			if (client.open(backupNode)) {
				com.yx.filesystem.storage.State stateObj=client.getStorageState(serverNode);
				if(stateObj.isSpaceFull()){
					return;
				}
				Hashtable<String, BigInteger> backupStorageState = stateObj.getFileState();
				if (backupStorageState.containsKey(serverNode.getId())) {
					String backupStorateFileTotalNumber = backupStorageState
							.get(serverNode.getId()).toString();
					backupStorateTimeStamp = Long
							.parseLong(backupStorateFileTotalNumber.substring(
									0, 14));
					beginTimeStampPointer = getBeginTimeStampPointer(backupStorateTimeStamp);
					beginStorateFileNumber = Long
							.parseLong(backupStorateFileTotalNumber
									.substring(14));
				}
				isConnect = true;
			}
		} catch (Throwable e) {
			return;
		} finally {
			client.close();
		}
		if (isConnect) {
			timestampFileNumbers[timestamps.length - 1] = getEndFileNumber();
			if (timestamps[beginTimeStampPointer] > backupStorateTimeStamp) {
				beginStorateFileNumber = -1;
			}
			for (int row = beginTimeStampPointer; row < timestamps.length; row++) {
				long timeStamp = timestamps[row];
				for (long col = (beginStorateFileNumber + 1); col <= timestampFileNumbers[row]; col++) {
					Archive file = new Archive(serverNode, timeStamp, col);
					if (file.exists()) {
						if (!backupFile(backupNode, file)) {
							return;
						}
						daemonSleep(300);
					}
				}
				beginStorateFileNumber = -1;
			}
		}

	}

	private boolean backupFile(Node backupNode, Archive file) {
		SocketClient client = new SocketClient();
		try {
			if (client.open(backupNode)) {
				String fileName = client.putFile(file);
				if (fileName.equals(file.getName())) {
					return true;
				}
			}
			return false;
		} catch (Throwable e) {
			return false;
		} finally {
			client.close();
		}
	}

	private int getBeginTimeStampPointer(long timsStamp) {
		for (int i = 0; i < timestamps.length; i++) {
			if (timsStamp <= timestamps[i])
				return i;
		}
		return timestamps.length;
	}

	private long getEndFileNumber() {
		try {
			Hashtable<String, BigInteger> state = Server.get()
					.getStorageSaveState();
			if (state.containsKey(serverNode.getId())) {
				String endSate = state.get(serverNode.getId()).toString();
				long endTimeStamp = Long.parseLong(endSate.substring(0, 14));
				long endFileNumber = Long.parseLong(endSate.substring(14));
				if (endTimeStamp == timestamps[timestamps.length - 1]) {
					return endFileNumber;
				}
			}
			return -1;
		} catch (Throwable e) {
			return -1;
		}
	}

	private void daemonSleep(long time) {
		synchronized (this) {
			try {
				wait(time);
			} catch (Exception e) {
				//e.printStackTrace();
				//System.out.println("Backup Server awaked!");
			}
		}

	}
	public void awakeDaemon() {
		synchronized (this) {
			this.notify();			
		}
	}

}
